package algorithm;

import java.util.Random;

public class Rule1Square implements Algorithm {
	
	protected int n, nvert, S, R, T, P;
	protected byte l[][];
	protected int Sum[][];
	protected int temp[][];
	protected boolean bPeriodic = false;
	protected int C = 0; // number of cooperating individuals
	
	/**
	 * 
	 * @param n - size of the matrix
	 * @param S - parameter of the simulation
	 * @param R - parameter of the simulation
	 * @param T - parameter of the simulation
	 * @param P - parameter of the simulation
	 * @param periodic
	 */
	public Rule1Square(int n, int S, int R, int T,int P, boolean periodic) {
		this.n = n;
		this.S = S;
		this.R = R;
		this.T = T;
		this.P = P;
		//P = 0;
		bPeriodic = periodic;
		Sum = new int[n][n];
		l = new byte[n][n];
		temp = new int[n][n];
		nvert = n * n;
	}


	@Override
	public void cycle(byte[] L) {
		// TODO Auto-generated method stub
		int p = 0;
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++)
			{
				temp[i][j] = 0;
				Sum[i][j] = 0;
				l[i][j] = L[p];
				p++;
			}
		}
		if(!bPeriodic) {		//Not Periodic
			// Sum calculation
			for( int i = 0; i < n; i++)
				for( int j = 0; j < n; j++) {
					if( i < n-1)
						lefele(l[i][j],l[i+1][j],i,j);
					if( j < n-1)
						jobbra(l[i][j],l[i][j+1],i,j);
				}
			
		// max strategy 
		for(int i = 0 ; i < n ; i++)
			for(int j = 0 ; j < n ; j++)
			{
				temp[i][j] = l[i][j];
				int max = Sum[i][j];
				
				if (i < n-1 && Sum[i + 1][j] > max) { temp[i][j] = l[i + 1][j]; max = Sum[i + 1][j]; }
				if (i > 0 && Sum[i - 1][j] > max) 	{ temp[i][j] = l[i - 1][j]; max = Sum[i - 1][j]; }
				if (j < n-1 && Sum[i][j + 1] > max) { temp[i][j] = l[i][j + 1]; max = Sum[i][j + 1]; }
				if (j > 0 && Sum[i][j - 1] > max) 	{ temp[i][j] = l[i][j - 1]; max = Sum[i][j - 1]; }
				
			}
			
		} else {		//Periodic
			//sum calculation
			for( int i = 0; i < n; i++) {
				for( int j = 0; j < n; j++) {
					if(i == n-1) { p_lefele(l[i][j], l[0][j], i, j); }
					if(j == n-1) { p_jobbra(l[i][j], l[i][0], i, j); }
					if(i < n-1)  { lefele(l[i][j],l[i+1][j],i,j); }
					if(j < n-1)  { jobbra(l[i][j],l[i][j+1],i,j); }
				}
			}
		
			// max strategy
			for(int i = 0; i < n ; i++) {
				for(int j = 0; j < n ; j++) {
					temp[i][j] = l[i][j];
					int max = Sum[i][j];
					
					if (i < n-1 && Sum[i + 1][j] > max) { temp[i][j] = l[i + 1][j]; max = Sum[i + 1][j]; }
					if (i > 0 && Sum[i - 1][j] > max) 	{ temp[i][j] = l[i - 1][j]; max = Sum[i - 1][j]; }
					if (j < n-1 && Sum[i][j + 1] > max) { temp[i][j] = l[i][j + 1]; max = Sum[i][j + 1]; }
					if (j > 0 && Sum[i][j - 1] > max) 	{ temp[i][j] = l[i][j - 1]; max = Sum[i][j - 1]; }
					if (i == 0 && Sum[n-1][j] > max) 	{ temp[i][j] = l[n-1][j]; max = Sum[n-1][j]; }
					if (j == 0 && Sum[i][n-1] > max) 	{ temp[i][j] = l[i][n - 1]; max = Sum[i][ n - 1]; }
					if (i == n-1 && Sum[0][j] > max) 	{ temp[i][j] = l[0][j]; max = Sum[0][j]; }
					if (j == n-1 && Sum[i][0] > max) 	{ temp[i][j] = l[i][0]; max = Sum[i][0]; }
					
				}
			}
		}
		
		C = 0;
		int r = 0;
		for (int i=0; i <n; i++) {
			   for (int j=0;j <n;j++) {
				  l[i][j]=(byte) temp[i][j];
				  L[r] = l[i][j];
				  r++;
				  if (l[i][j] == 1) {
					  C++;
				  }
			  }
		}

	}

	/**
	 * Initialize the matrix randomly
	 */
	@Override
	public byte[] init() {
		// TODO Auto-generated method stub
		byte[] matrix = new byte[nvert];
		Random rand = new Random();
		byte randnumber;
		C = 0;
		
		for(int i=0; i < nvert-1; i++) {
			randnumber = (byte) rand.nextInt(2);
			matrix[i] = randnumber;
			if (randnumber == 1) {
				C++;
			}
		}
		
		return matrix;
	}

	@Override
	public int getC() {
		// TODO Auto-generated method stub
		return C;
	}

	@Override
	public int getD() {
		// TODO Auto-generated method stub
		return nvert - C;
	}
	
	/**
	 * 
	 * @param strategia1
	 * @param strategia2
	 * @param i
	 * @param j
	 */
	private void jobbra(int strategia1, int strategia2, int i, int j) {
		if ( strategia1 == 1 && strategia2 == 1) { 		//Cooperate - Cooperate
			Sum[i][j] = Sum[i][j] + R;
			Sum[i][j+1] = Sum[i][j+1] + R;
		}
		
		if ( strategia1 == 1 && strategia2 == 0) { 		 //Cooperate - Defect
			Sum[i][j] = Sum[i][j] + P;
			Sum[i][j+1] = Sum[i][j+1] + T;
		}		
		
		if ( strategia1 == 0 && strategia2 == 1) { 		//Defect - Cooperate
			Sum[i][j] = Sum[i][j] + T;
			Sum[i][j+1] = Sum[i][j+1] + P;
		}
		
		if ( strategia1 == 0 && strategia2 == 0) { 		//Defect - Defect
			Sum[i][j] = Sum[i][j] + S;
			Sum[i][j+1] = Sum[i][j+1] + S;
		}
	}
	
	/**
	 * 
	 * @param strategia1
	 * @param strategia2
	 * @param i
	 * @param j
	 */
	private void lefele(int strategia1,int strategia2,int i, int j) {
		if ( strategia1 == 1 && strategia2 == 1) { 		 //Cooperate - Cooperate
			Sum[i][j] = Sum[i][j] + R;
			Sum[i+1][j] = Sum[i+1][j] + R;
		}
		
		if ( strategia1 == 1 && strategia2 == 0) { 		 //Cooperate - Defect
			Sum[i][j] = Sum[i][j] + P;
			Sum[i+1][j] = Sum[i+1][j] + T;
		}		
		
		if ( strategia1 == 0 && strategia2 == 1) { 		//Defect - Coopereate
			Sum[i][j] = Sum[i][j] + T;
			Sum[i+1][j] = Sum[i+1][j] + P;
		}
		
		if ( strategia1 == 0 && strategia2 == 0) { 		//Defect - Defect
			Sum[i][j] = Sum[i][j] + S;
			Sum[i+1][j] = Sum[i+1][j] + S;
		}
	}
	
	/**
	 * 
	 * @param strategia1
	 * @param strategia2
	 * @param i
	 * @param j
	 */
	private void p_jobbra(int strategia1,int strategia2,int i, int j) {
		if ( strategia1 == 1 && strategia2 == 1) { 		 //Cooperate - Cooperate
			Sum[i][j] = Sum[i][j] + R;
			Sum[i][0] = Sum[i][0] + R;
		}
		
		if ( strategia1 == 1 && strategia2 == 0) { 		 //Cooperate - Defect
			Sum[i][j] = Sum[i][j] + P;
			Sum[i][0] = Sum[i][0] + T;
		}		
		
		if ( strategia1 == 0 && strategia2 == 1) { 		//Defect - Coopereate
			Sum[i][j] = Sum[i][j] + T;
			Sum[i][0] = Sum[i][0] + P;
		}
		
		if ( strategia1 == 0 && strategia2 == 0) { 		//Defect - Defect
			Sum[i][j] = Sum[i][j] + S;
			Sum[i][0] = Sum[i][0] + S;
		}
	}
	
	/**
	 * 
	 * @param strategia1
	 * @param strategia2
	 * @param i
	 * @param j
	 */
	private void p_lefele(int strategia1,int strategia2,int i, int j) {
		if ( strategia1 == 1 && strategia2 == 1) { 		 //Cooperate - Cooperate
			Sum[i][j] = Sum[i][j] + R;
			Sum[0][j] = Sum[0][j] + R;
		}
		
		if ( strategia1 == 1 && strategia2 == 0) { 		 //Cooperate - Defect
			Sum[i][j] = Sum[i][j] + P;
			Sum[0][j] = Sum[0][j] + T;
		}		
		
		if ( strategia1 == 0 && strategia2 == 1) { 		//Defect - Coopereate
			Sum[i][j] = Sum[i][j] + T;
			Sum[0][j] = Sum[0][j] + P;
		}
		
		if ( strategia1 == 0 && strategia2 == 0) { 		//Defect - Defect
			Sum[i][j] = Sum[i][j] + S;
			Sum[0][j] = Sum[0][j] + S;
		}
	}
	

}
